﻿Imports System.ComponentModel

Public MustInherit Class BaseViewModel
  Implements IDisposable, INotifyPropertyChanged

#Region "INotifyPropertyChanged Members"

  ''' <summary>
  ''' Raised when a property on this object has a new value.
  ''' </summary>
  Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged

  ''' <summary>
  ''' Raises this object's PropertyChanged event.
  ''' </summary>
  ''' <param name="propertyName">The property that has a new value.</param>
  Protected Overridable Sub OnPropertyChanged(ByVal propertyName As String)
    Me.VerifyPropertyName(propertyName)

    Dim handler As PropertyChangedEventHandler = Me.PropertyChangedEvent
    If handler IsNot Nothing Then
      Dim e = New PropertyChangedEventArgs(propertyName)
      handler(Me, e)
    End If
  End Sub

#End Region ' INotifyPropertyChanged Members

#Region " IDisposable Support "

  Private disposedValue As Boolean = False    ' To detect redundant calls

  ' IDisposable
  Protected Overridable Sub Dispose(ByVal disposing As Boolean)
    If Not Me.disposedValue Then
      If disposing Then
        ' TODO: free other state (managed objects).
      End If

      ' TODO: free your own state (unmanaged objects).
      ' TODO: set large fields to null.
    End If
    Me.disposedValue = True
  End Sub

  ' This code added by Visual Basic to correctly implement the disposable pattern.
  Public Sub Dispose() Implements IDisposable.Dispose
    ' Do not change this code.  Put cleanup code in Dispose(ByVal disposing As Boolean) above.
    Dispose(True)
    GC.SuppressFinalize(Me)
  End Sub
#End Region

#Region "Debugging Aides"

  ''' <summary>
  ''' Warns the developer if this object does not have
  ''' a public property with the specified name. This 
  ''' method does not exist in a Release build.
  ''' </summary>
  <Conditional("DEBUG"), DebuggerStepThrough()> _
  Public Sub VerifyPropertyName(ByVal propertyName As String)
    ' Verify that the property name matches a real,  
    ' public, instance property on this object.
    If TypeDescriptor.GetProperties(Me)(propertyName) Is Nothing Then
      Dim msg As String = "Invalid property name: " & propertyName

      If Me.ThrowOnInvalidPropertyName Then
        Throw New Exception(msg)
      Else
        Debug.Fail(msg)
      End If
    End If
  End Sub

  ''' <summary>
  ''' Returns whether an exception is thrown, or if a Debug.Fail() is used
  ''' when an invalid property name is passed to the VerifyPropertyName method.
  ''' The default value is false, but subclasses used by unit tests might 
  ''' override this property's getter to return true.
  ''' </summary>
  Private privateThrowOnInvalidPropertyName As Boolean
  Protected Overridable Property ThrowOnInvalidPropertyName() As Boolean
    Get
      Return privateThrowOnInvalidPropertyName
    End Get
    Set(ByVal value As Boolean)
      privateThrowOnInvalidPropertyName = value
    End Set
  End Property

#End Region ' Debugging Aides

End Class
